const SEED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const BOARD_CHARS = ["▓", "１", "２", "３", "４", "５", "６", "７", "８"];
const MINE = "雷";
const DEFAULT_SEED_LENGTH = 8;
const DEBUG = false;

function log() {
    if (DEBUG) {
        console.log(...arguments);
    }
}
function make_seed(len = DEFAULT_SEED_LENGTH) {
    var ret = "";
    for (var i = 0; i < len; i++) {
        ret += SEED_CHARS.charAt(Math.floor(Math.random() * SEED_CHARS.length));
    }
    return ret;
}
function inc_counter(board, r0, c0) {
    for (var r = r0 - 1; r <= r0 + 1; r++) {
        for (var c = c0 - 1; c <= c0 + 1; c++) {
            if (0 <= r && r < board.length &&
                0 <= c && c < board[r].length &&
                board[r][c] !== MINE) {
                board[r][c]++;
            }
        }
    }
}
function array_to_string(board, prefix = "", suffix = "") {
    var s = "";
    for (var r = 0; r < board.length; r++) {
        for (var c = 0; c < board[r].length; c++) {
            s += prefix + board[r][c].toString() + suffix;
        }
        s += "\n";
    }
    return s
}
function create_board_from_bitset(flattened, height, width) {
    var ret = new Array(height);
    var idx = 0;
    for (var r = 0; r < height; r++) {
        var row = new Array(width);
        for (var c = 0; c < width; c++) {
            row[c] = flattened[idx] ? MINE : 0;
            idx++;
        }
        ret[r] = row;
    }
    log(array_to_string(ret));
    for (var r = 0; r < height; r++) {
        for (var c = 0; c < width; c++) {
            if (ret[r][c] === MINE) {
                inc_counter(ret, r, c);
            }
        }
    }
    log(array_to_string(ret));
    for (var r = 0; r < height; r++) {
        for (var c = 0; c < width; c++) {
            if (ret[r][c] !== MINE) {
                ret[r][c] = BOARD_CHARS[ret[r][c]];
            }
        }
    }
    log(array_to_string(ret));
    return ret;
}
class Board {
    constructor(options) {
        if (typeof options === "undefined") {
            options = {};
        }
        this.height = options["height"];
        this.width = options["width"];
        this.num_mines = options["num_mines"];
        this.seed = options["seed"];
    }
    set_defaults() {
        if (typeof this.height === "undefined" || !this.height) {
            this.height = 16;
        }
        if (typeof this.width === "undefined" || !this.width) {
            this.width = 16;
        }
        if (typeof this.num_mines === "undefined" || !this.num_mines) {
            this.num_mines = Math.floor(this.width * this.height * 0.05);
        }
        if (typeof this.seed === "undefined" || !this.seed) {
            this.seed = make_seed();
        }
    }
    generate() {
        this.set_defaults();
        var board_size = this.width * this.height;
        if (this.num_mines > board_size) {
            return false;
        }
        var flattened = new Array(board_size)
        for (var i = 0; i < board_size; i++) {
            flattened[i] = false;
        }
        var existing_mines = 0;
        var current_index = 0;
        var rng = new Math.seedrandom(this.seed);
        while (existing_mines < this.num_mines) {
            if (!flattened[current_index]) {
                var probability = (this.num_mines - existing_mines) / (board_size - existing_mines);
                var should_place = (rng() < probability);
                flattened[current_index] = should_place;
                existing_mines += (should_place ? 1 : 0);
            }
            current_index++;
            current_index %= flattened.length;
        }
        this.board = create_board_from_bitset(flattened, this.height, this.width)
        return true;
    }
    debug_print() {
        log(array_to_string(this.board))
        log("seed=" + this.seed)
    }
    get_adnmb_string() {
        return array_to_string(this.board, "[h]", "[/h] ")
    }
}
function show_message(text) {
    $("#message").stop(true);
    $("#message").fadeOut(0, function() {
        $("#message").text(text);
        $("#message").fadeIn().delay(1000).fadeOut(function() {
            $("#message").html("&nbsp;");
        });
    });
}
function generate_and_show() {
    var attrs = ["width", "height", "num_mines", "seed"];
    var options = {}
    attrs.forEach(function(attr) {
        var val = $("#" + attr).val()
        if (attr !== "seed") {
            val = parseInt(val);
            if (isNaN(val)) val = undefined;
        }
        options[attr] = val;
    });
    var board = new Board(options);
    board.set_defaults();
    attrs.forEach(function(attr) {
        $("#" + attr).val(board[attr]);
    });
    if (!board.generate()) {
        show_message("太多地雷了！");
        return;
    }
    var board_str = board.get_adnmb_string();
    $("#output").val(board_str);
    log(board_str);
}
function reseed() {
    $("#seed").val(make_seed());
    generate_and_show();
}
$(document).ready(function() {
    var clipboard = new ClipboardJS("#copy");
    clipboard.on('success', function(e) {
        show_message("已复制！");
        e.clearSelection();
    });

    clipboard.on('error', function(e) {
        show_message("无法复制！");
    });
});
